{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "b518b04cbfe0"
      },
      "source": [
        "##### Copyright 2020 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "906e07f6e562"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6e083398b477"
      },
      "source": [
        "# 전처리 레이어 처리"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "64010bd23c2e"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/guide/keras/preprocessing_layers\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">TensorFlow.org에서 보기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ko/guide/keras/preprocessing_layers.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Google Colab에서 실행</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ko/guide/keras/preprocessing_layers.ipynb\">     <img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">    GitHub에서 소스 보기</a></td>\n",
        "  <td><a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ko/guide/keras/preprocessing_layers.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">노트북 다운로드</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5387d1418bf5"
      },
      "source": [
        "## Keras 전처리 레이어\n",
        "\n",
        "Keras 전처리 레이어 API를 사용하면 개발자가 Keras 네이티브 입력 처리 파이프라인을 빌드할 수 있습니다. 이러한 입력 처리 파이프라인은 Keras가 아닌 워크플로에서 독립적인 전처리 코드로 사용하고, Keras 모델과 직접 결합하고, Keras SavedModel의 일부로 내보낼 수 있습니다.\n",
        "\n",
        "Keras 전처리 레이어를 사용하면 진정한 엔드 투 엔드 모델(원시 이미지 또는 원시 구조적 데이터를 입력으로 받아들이는 모델과 특성 정규화 또는 특성 값 인덱싱을 자체적으로 처리하는 모델)을 빌드하고 내보낼 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "338796ee379c"
      },
      "source": [
        "## 사용 가능한 전처리 레이어\n",
        "\n",
        "### 핵심 전처리 레이어\n",
        "\n",
        "- `TextVectorization` 레이어: 원시 문자열을 `Embedding` 레이어 또는 `Dense` 레이어에서 읽을 수 있는 인코딩된 표현으로 변환합니다.\n",
        "- `Normalization` 레이어: 입력 특성의 특성별 정규화를 수행합니다.\n",
        "\n",
        "### 구조적 데이터 전처리 레이어\n",
        "\n",
        "다음 레이어는 구조적 데이터 인코딩 및 특성 엔지니어링을 위한 것입니다.\n",
        "\n",
        "- `CategoryEncoding` 레이어: 정수 범주형 특성을 원-핫, 멀티-핫 또는 TF-IDF 밀도 표현으로 바꿉니다.\n",
        "- `Hashing` 레이어: \"해싱 트릭(hashing trick)\"이라고도 하는 범주형 특성 해싱을 수행합니다.\n",
        "- `Discretization` 레이어: 연속적인 숫자 특성을 정수 범주형 특성으로 바꿉니다.\n",
        "- `StringLookup` 레이어: 문자열 범주형 값을 정수 인덱스로 바꿉니다.\n",
        "- `IntegerLookup` 레이어: 정수 범주형 값을 정수 인덱스로 바꿉니다.\n",
        "- `CategoryCrossing` 레이어: 범주형 특성을 동시 발생 특성으로 결합합니다. 예를 들어, 특성 값 \"a\"와 \"b\"가 있는 경우, \"a와 b가 동시에 존재\"하는 조합 특성을 제공할 수 있습니다.\n",
        "\n",
        "### 이미지 전처리 레이어\n",
        "\n",
        "다음 레이어는 이미지 모델의 입력을 표준화하기 위한 것입니다.\n",
        "\n",
        "- `Resizing` 레이어: 이미지 배치의 크기를 목표 크기로 조정합니다.\n",
        "- `Rescaling` 레이어: 이미지 배치의 값을 다시 조정하고 상쇄합니다(예: `[0, 255]` 범위의 입력에서 `[0, 1]` 범위의 입력으로 이동).\n",
        "- `CenterCrop` 레이어: 이미지 배치인 경우 중앙 자르기를 반환합니다.\n",
        "\n",
        "### 이미지 데이터 증대 레이어\n",
        "\n",
        "이들 레이어는 이미지 배치에 무작위 증대 변환을 적용합니다. 훈련 중에만 활성화됩니다.\n",
        "\n",
        "- `RandomCrop` 레이어\n",
        "- `RandomFlip` 레이어\n",
        "- `RandomTranslation` 레이어\n",
        "- `RandomRotation` 레이어\n",
        "- `RandomZoom` 레이어\n",
        "- `RandomHeight` 레이어\n",
        "- `RandomWidth` 레이어"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "672e84af6eb7"
      },
      "source": [
        "## `adapt()` 메서드\n",
        "\n",
        "일부 전처리 레이어에는 훈련 데이터의 샘플을 기반으로 계산해야 하는 내부 상태가 있습니다. 상태 저장 전처리 레이어의 목록은 다음과 같습니다.\n",
        "\n",
        "- `TextVectorization`: 문자열 토큰과 정수 인덱스 간의 매핑을 보유합니다.\n",
        "- `Normalization`: 특성의 평균 및 표준 편차를 보유합니다.\n",
        "- `StringLookup` 및 `IntegerLookup`: 입력 값과 출력 인덱스 간의 매핑을 보유합니다.\n",
        "- `CategoryEncoding` : 입력 값의 색인을 보유합니다.\n",
        "- `Discretization` : 값 버킷 경계에 대한 정보를 보유합니다.\n",
        "\n",
        "결정적으로, 이러한 레이어는 **훈련 불가능**합니다. 이들의 상태는 훈련 중에 설정되지 않습니다. **훈련 전에** 설정해야 합니다. 이 단계를 \"적응(adaptation)\"이라고 합니다.\n",
        "\n",
        "`adapt()` 메서드를 통해 전처리 레이어의 상태를 훈련 데이터에 노출함으로써 상태를 설정할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "e05c8fc4d032"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import tensorflow as tf\n",
        "from tensorflow.keras.layers.experimental import preprocessing\n",
        "\n",
        "data = np.array([[0.1, 0.2, 0.3], [0.8, 0.9, 1.0], [1.5, 1.6, 1.7],])\n",
        "layer = preprocessing.Normalization()\n",
        "layer.adapt(data)\n",
        "normalized_data = layer(data)\n",
        "\n",
        "print(\"Features mean: %.2f\" % (normalized_data.numpy().mean()))\n",
        "print(\"Features std: %.2f\" % (normalized_data.numpy().std()))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "d43b8246b8a3"
      },
      "source": [
        "`adapt()` 메소드는 Numpy 배열 또는 `tf.data.Dataset` 객체를 사용합니다. `StringLookup` 및 `TextVectorization` 의 경우, 문자열의 목록을 전달할 수도 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "74ef94620592"
      },
      "outputs": [],
      "source": [
        "data = [\n",
        "    \"ξεῖν᾽, ἦ τοι μὲν ὄνειροι ἀμήχανοι ἀκριτόμυθοι\",\n",
        "    \"γίγνοντ᾽, οὐδέ τι πάντα τελείεται ἀνθρώποισι.\",\n",
        "    \"δοιαὶ γάρ τε πύλαι ἀμενηνῶν εἰσὶν ὀνείρων:\",\n",
        "    \"αἱ μὲν γὰρ κεράεσσι τετεύχαται, αἱ δ᾽ ἐλέφαντι:\",\n",
        "    \"τῶν οἳ μέν κ᾽ ἔλθωσι διὰ πριστοῦ ἐλέφαντος,\",\n",
        "    \"οἵ ῥ᾽ ἐλεφαίρονται, ἔπε᾽ ἀκράαντα φέροντες:\",\n",
        "    \"οἱ δὲ διὰ ξεστῶν κεράων ἔλθωσι θύραζε,\",\n",
        "    \"οἵ ῥ᾽ ἔτυμα κραίνουσι, βροτῶν ὅτε κέν τις ἴδηται.\",\n",
        "]\n",
        "layer = preprocessing.TextVectorization()\n",
        "layer.adapt(data)\n",
        "vectorized_text = layer(data)\n",
        "print(vectorized_text)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7619914dfb40"
      },
      "source": [
        "또한, 적응 가능한 레이어는 항상 생성자 인수 또는 가중치 할당을 통해 상태를 직접 설정하는 옵션을 제공합니다. 의도한 상태 값이 레이어 생성 시 알려지거나 `adapt()` 호출 외부에서 계산되는 경우, 레이어의 내부 계산에 의존하지 않고 설정할 수 있습니다. 예를 들어, `TextVectorization` , `StringLookup` 또는 `IntegerLookup` 레이어에 대한 외부 어휘 파일이 이미 있는 경우, 레이어의 생성자 인수에 있는 어휘 파일에 대한 경로를 전달하여 조회 테이블에 직접 로드할 수 있습니다.\n",
        "\n",
        "다음은 사전 계산된 어휘로 `StringLookup` 레이어를 인스턴스화하는 예입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "76aeb9346838"
      },
      "outputs": [],
      "source": [
        "vocab = [\"a\", \"b\", \"c\", \"d\"]\n",
        "data = tf.constant([[\"a\", \"c\", \"d\"], [\"d\", \"z\", \"b\"]])\n",
        "layer = preprocessing.StringLookup(vocabulary=vocab)\n",
        "vectorized_data = layer(data)\n",
        "print(vectorized_data)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3cd07d2533da"
      },
      "source": [
        "## 모델 전 또는 모델 내부의 데이터 전처리\n",
        "\n",
        "전처리 레이어를 사용할 수 있는 두 가지 방법이 있습니다.\n",
        "\n",
        "**옵션 1:** 다음과 같이 전처리 레이어를 모델의 일부로 만듭니다.\n",
        "\n",
        "```python\n",
        "inputs = keras.Input(shape=input_shape)\n",
        "x = preprocessing_layer(inputs)\n",
        "outputs = rest_of_the_model(x)\n",
        "model = keras.Model(inputs, outputs)\n",
        "```\n",
        "\n",
        "이 옵션을 사용하면 나머지 모델 실행과 동시에 기기에서 전처리가 이루어지므로 GPU 가속의 이점이 있습니다. GPU에서 훈련하는 경우, `Normalization` 레이어와 모든 이미지 전처리 및 데이터 증대 레이어에 가장 적합한 옵션입니다.\n",
        "\n",
        "**옵션 2:** `tf.data.Dataset`에 전처리 레이어를 적용하여 다음과 같이 전처리된 데이터의 배치를 생성하는 데이터세트를 얻습니다.\n",
        "\n",
        "```python\n",
        "dataset = dataset.map(\n",
        "  lambda x, y: (preprocessing_layer(x), y))\n",
        "```\n",
        "\n",
        "이 옵션을 사용하면 전처리가 CPU에서 비동기적으로 발생하고 모델로 이동하기 전에 버퍼링됩니다.\n",
        "\n",
        "이 옵션은 `TextVectorization` 및 모든 구조적 데이터 전처리 레이어에 가장 적합한 옵션입니다. CPU에서 훈련하고 이미지 전처리 레이어를 사용하는 경우에도 좋은 옵션이 될 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "32f6d2a104b7"
      },
      "source": [
        "## 추론 시 모델 내에서 전처리를 수행할 때의 이점\n",
        "\n",
        "옵션 2를 사용하더라도 나중에 전처리 레이어를 포함하는 추론 전용 엔드 투 엔드 모델을 내보낼 수 있습니다. 이 작업의 주요 이점은 **모델을 이식 가능하게 만들고** **[훈련/적용 편향](https://developers.google.com/machine-learning/guides/rules-of-ml#training-serving_skew)**을 줄이는 데 도움이 된다는 것입니다.\n",
        "\n",
        "모든 데이터 전처리가 모델의 일부인 경우, 다른 사람들은 각 특성이 어떻게 인코딩되고 정규화될 것으로 예상되는지 알 필요 없이 모델을 로드하고 사용할 수 있습니다. 추론 모델은 원시 이미지 또는 원시 구조적 데이터를 처리할 수 있으며, 모델 사용자가 예를 들어, 텍스트에 사용되는 토큰화 체계, 범주형 특성에 사용되는 인덱싱 체계, 이미지 픽셀 값이 `[-1, +1]` 또는 `[0, 1]`로 정규화되었는지 여부와 같은 세부 정보를 알 필요가 없습니다. 이는 모델을 TensorFlow.js와 같은 다른 런타임으로 내보내는 경우 특히 강력합니다. JavaScript에서 전처리 파이프라인을 다시 구현할 필요가 없습니다.\n",
        "\n",
        "처음에 전처리 레이어를 `tf.data` 파이프라인에 배치한 경우, 전처리를 패키징하는 추론 모델을 내보낼 수 있습니다. 전처리 레이어와 훈련 모델을 연결하는 새 모델을 인스턴스화하기만 하면 됩니다.\n",
        "\n",
        "```python\n",
        "inputs = keras.Input(shape=input_shape)\n",
        "x = preprocessing_layer(inputs)\n",
        "outputs = training_model(x)\n",
        "inference_model = keras.Model(inputs, outputs)\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ff9bad6ba7d5"
      },
      "source": [
        "## 빠른 레시피\n",
        "\n",
        "### 이미지 데이터 증대(기기 내)\n",
        "\n",
        "이미지 데이터 증대 레이어는 훈련 중에만 활성화됩니다(`Dropout` 레이어와 유사)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "a621c2645ae6"
      },
      "outputs": [],
      "source": [
        "from tensorflow import keras\n",
        "from tensorflow.keras import layers\n",
        "\n",
        "# Create a data augmentation stage with horizontal flipping, rotations, zooms\n",
        "data_augmentation = keras.Sequential(\n",
        "    [\n",
        "        preprocessing.RandomFlip(\"horizontal\"),\n",
        "        preprocessing.RandomRotation(0.1),\n",
        "        preprocessing.RandomZoom(0.1),\n",
        "    ]\n",
        ")\n",
        "\n",
        "# Create a model that includes the augmentation stage\n",
        "input_shape = (32, 32, 3)\n",
        "classes = 10\n",
        "inputs = keras.Input(shape=input_shape)\n",
        "# Augment images\n",
        "x = data_augmentation(inputs)\n",
        "# Rescale image values to [0, 1]\n",
        "x = preprocessing.Rescaling(1.0 / 255)(x)\n",
        "# Add the rest of the model\n",
        "outputs = keras.applications.ResNet50(\n",
        "    weights=None, input_shape=input_shape, classes=classes\n",
        ")(x)\n",
        "model = keras.Model(inputs, outputs)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "51d369f0310f"
      },
      "source": [
        "[처음부터 이미지 분류하기](https://keras.io/examples/vision/image_classification_from_scratch/) 예제에서 유사한 설정이 동작하는 것을 볼 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "a79a1c48b2b7"
      },
      "source": [
        "### 수치 특성 정규화하기"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "f5a7c8f6270b"
      },
      "outputs": [],
      "source": [
        "# Load some data\n",
        "(x_train, y_train), _ = keras.datasets.cifar10.load_data()\n",
        "x_train = x_train.reshape((len(x_train), -1))\n",
        "input_shape = x_train.shape[1:]\n",
        "classes = 10\n",
        "\n",
        "# Create a Normalization layer and set its internal state using the training data\n",
        "normalizer = preprocessing.Normalization()\n",
        "normalizer.adapt(x_train)\n",
        "\n",
        "# Create a model that include the normalization layer\n",
        "inputs = keras.Input(shape=input_shape)\n",
        "x = normalizer(inputs)\n",
        "outputs = layers.Dense(classes, activation=\"softmax\")(x)\n",
        "model = keras.Model(inputs, outputs)\n",
        "\n",
        "# Train the model\n",
        "model.compile(optimizer=\"adam\", loss=\"sparse_categorical_crossentropy\")\n",
        "model.fit(x_train, y_train)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "62685d477010"
      },
      "source": [
        "### 원-핫 인코딩을 통해 문자열 범주형 특성 인코딩하기"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "36303d995404"
      },
      "outputs": [],
      "source": [
        "# Define some toy data\n",
        "data = tf.constant([\"a\", \"b\", \"c\", \"b\", \"c\", \"a\"])\n",
        "\n",
        "# Use StringLookup to build an index of the feature values\n",
        "indexer = preprocessing.StringLookup()\n",
        "indexer.adapt(data)\n",
        "\n",
        "# Use CategoryEncoding to encode the integer indices to a one-hot vector\n",
        "encoder = preprocessing.CategoryEncoding(output_mode=\"binary\")\n",
        "encoder.adapt(indexer(data))\n",
        "\n",
        "# Convert new test data (which includes unknown feature values)\n",
        "test_data = tf.constant([\"a\", \"b\", \"c\", \"d\", \"e\", \"\"])\n",
        "encoded_data = encoder(indexer(test_data))\n",
        "print(encoded_data)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3d88c64d9b33"
      },
      "source": [
        "인덱스 0은 누락된 값(빈 문자열 `\"\"`로 지정해야 함)을 위해 예약되고, 인덱스 1은 어휘를 벗어난 값(`adapt()` 동안 표시되지 않은 값)을 위해 예약되어 있습니다. `mask_token` 및 `StringLookup`의 `oov_token` 생성자 인수를 사용하여 이를 구성할 수 있습니다.\n",
        "\n",
        "[처음부터 구조적 데이터 분류하기](https://keras.io/examples/structured_data/structured_data_classification_from_scratch/) 예제에서 동작 중인 `StringLookup` 및 `CategoryEncoding` 레이어를 볼 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dc8af3e290df"
      },
      "source": [
        "### 원-핫 인코딩을 통해 정수 범주형 특성 인코딩하기"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "e55f069cbdf5"
      },
      "outputs": [],
      "source": [
        "# Define some toy data\n",
        "data = tf.constant([10, 20, 20, 10, 30, 0])\n",
        "\n",
        "# Use IntegerLookup to build an index of the feature values\n",
        "indexer = preprocessing.IntegerLookup()\n",
        "indexer.adapt(data)\n",
        "\n",
        "# Use CategoryEncoding to encode the integer indices to a one-hot vector\n",
        "encoder = preprocessing.CategoryEncoding(output_mode=\"binary\")\n",
        "encoder.adapt(indexer(data))\n",
        "\n",
        "# Convert new test data (which includes unknown feature values)\n",
        "test_data = tf.constant([10, 10, 20, 50, 60, 0])\n",
        "encoded_data = encoder(indexer(test_data))\n",
        "print(encoded_data)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "82830d172b7f"
      },
      "source": [
        "인덱스 0은 누락된 값(값 0으로 지정해야 함)을 위해 예약되고, 인덱스 1은 어휘를 벗어난 값(`adapt()` 동안 표시되지 않은 값)을 위해 예약되어 있습니다. `mask_value` 및 `IntegerLookup`의 `oov_value` 생성자 인수를 사용하여 이를 구성할 수 있습니다.\n",
        "\n",
        "[처음부터 구조적 데이터 분류하기](https://keras.io/examples/structured_data/structured_data_classification_from_scratch/) 예제에서 동작 중인 `IntegerLookup` 및 `CategoryEncoding` 레이어를 볼 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8fbfaa6ab3e2"
      },
      "source": [
        "### 정수 범주형 특성에 해싱 트릭 적용하기\n",
        "\n",
        "여러 다른 값(10e3 이상)을 사용할 수 있는 범주형 특성의 각 값이 데이터에서 몇 번만 나타나는 경우, 특성 값을 인덱싱하고 원-핫 인코딩하는 것은 비실용적이고 비효율적입니다. 대신, \"해싱 트릭\"을 적용하는 것이 좋습니다. 값을 고정된 크기의 벡터로 해싱합니다. 이는 특성 공간의 크기를 관리 가능한 상태로 유지하고 명시적 인덱싱의 필요성을 제거합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2def8456f905"
      },
      "outputs": [],
      "source": [
        "# Sample data: 10,000 random integers with values between 0 and 100,000\n",
        "data = np.random.randint(0, 100000, size=(10000, 1))\n",
        "\n",
        "# Use the Hashing layer to hash the values to the range [0, 64]\n",
        "hasher = preprocessing.Hashing(num_bins=64, salt=1337)\n",
        "\n",
        "# Use the CategoryEncoding layer to one-hot encode the hashed values\n",
        "encoder = preprocessing.CategoryEncoding(max_tokens=64, output_mode=\"binary\")\n",
        "encoded_data = encoder(hasher(data))\n",
        "print(encoded_data.shape)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "df69b434d327"
      },
      "source": [
        "### 일련의 토큰 인덱스로 텍스트 인코딩하기\n",
        "\n",
        "`Embedding` 레이어에 전달될 텍스트를 전처리하는 방법입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "a689d9dcf6ab"
      },
      "outputs": [],
      "source": [
        "# Define some text data to adapt the layer\n",
        "data = tf.constant(\n",
        "    [\n",
        "        \"The Brain is wider than the Sky\",\n",
        "        \"For put them side by side\",\n",
        "        \"The one the other will contain\",\n",
        "        \"With ease and You beside\",\n",
        "    ]\n",
        ")\n",
        "# Instantiate TextVectorization with \"int\" output_mode\n",
        "text_vectorizer = preprocessing.TextVectorization(output_mode=\"int\")\n",
        "# Index the vocabulary via `adapt()`\n",
        "text_vectorizer.adapt(data)\n",
        "\n",
        "# You can retrieve the vocabulary we indexed via get_vocabulary()\n",
        "vocab = text_vectorizer.get_vocabulary()\n",
        "print(\"Vocabulary:\", vocab)\n",
        "\n",
        "# Create an Embedding + LSTM model\n",
        "inputs = keras.Input(shape=(1,), dtype=\"string\")\n",
        "x = text_vectorizer(inputs)\n",
        "x = layers.Embedding(input_dim=len(vocab), output_dim=64)(x)\n",
        "outputs = layers.LSTM(1)(x)\n",
        "model = keras.Model(inputs, outputs)\n",
        "\n",
        "# Call the model on test data (which includes unknown tokens)\n",
        "test_data = tf.constant([\"The Brain is deeper than the sea\"])\n",
        "test_output = model(test_data)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "a84d4f2ec0ef"
      },
      "source": [
        "<a>처음부터 텍스트 분류</a> 예에서 `Embedding` 모드와 결합된 <code>TextVectorization</code> 레이어가 동작하는 것을 볼 수 있습니다.\n",
        "\n",
        "이러한 모델을 훈련할 때 최상의 성능을 위해 `TextVectorization` 레이어를 입력 파이프라인(위의 텍스트 분류 예제에서 수행한 작업)의 일부로 사용해야 합니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "28c2f2ff61fb"
      },
      "source": [
        "### 멀티-핫 인코딩을 사용하여 텍스트를 ngram의 밀집 행렬로 인코딩하기\n",
        "\n",
        "다음은 `Dense` 레이어로 전달될 텍스트를 전처리하는 방법입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "b62472e32529"
      },
      "outputs": [],
      "source": [
        "# Define some text data to adapt the layer\n",
        "data = tf.constant(\n",
        "    [\n",
        "        \"The Brain is wider than the Sky\",\n",
        "        \"For put them side by side\",\n",
        "        \"The one the other will contain\",\n",
        "        \"With ease and You beside\",\n",
        "    ]\n",
        ")\n",
        "# Instantiate TextVectorization with \"binary\" output_mode (multi-hot)\n",
        "# and ngrams=2 (index all bigrams)\n",
        "text_vectorizer = preprocessing.TextVectorization(output_mode=\"binary\", ngrams=2)\n",
        "# Index the bigrams via `adapt()`\n",
        "text_vectorizer.adapt(data)\n",
        "\n",
        "print(\n",
        "    \"Encoded text:\\n\",\n",
        "    text_vectorizer([\"The Brain is deeper than the sea\"]).numpy(),\n",
        "    \"\\n\",\n",
        ")\n",
        "\n",
        "# Create a Dense model\n",
        "inputs = keras.Input(shape=(1,), dtype=\"string\")\n",
        "x = text_vectorizer(inputs)\n",
        "outputs = layers.Dense(1)(x)\n",
        "model = keras.Model(inputs, outputs)\n",
        "\n",
        "# Call the model on test data (which includes unknown tokens)\n",
        "test_data = tf.constant([\"The Brain is deeper than the sea\"])\n",
        "test_output = model(test_data)\n",
        "\n",
        "print(\"Model output:\", test_output)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "336a4d3426ed"
      },
      "source": [
        "### TF-IDF 가중치를 사용하여 텍스트를 ngram의 밀집 행렬로 인코딩하기\n",
        "\n",
        "다음은 `Dense` 레이어로 전달하기 전에 텍스트를 전처리하는 또 다른 방법입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "cdf16938fe7c"
      },
      "outputs": [],
      "source": [
        "# Define some text data to adapt the layer\n",
        "data = tf.constant(\n",
        "    [\n",
        "        \"The Brain is wider than the Sky\",\n",
        "        \"For put them side by side\",\n",
        "        \"The one the other will contain\",\n",
        "        \"With ease and You beside\",\n",
        "    ]\n",
        ")\n",
        "# Instantiate TextVectorization with \"tf-idf\" output_mode\n",
        "# (multi-hot with TF-IDF weighting) and ngrams=2 (index all bigrams)\n",
        "text_vectorizer = preprocessing.TextVectorization(output_mode=\"tf-idf\", ngrams=2)\n",
        "# Index the bigrams and learn the TF-IDF weights via `adapt()`\n",
        "text_vectorizer.adapt(data)\n",
        "\n",
        "print(\n",
        "    \"Encoded text:\\n\",\n",
        "    text_vectorizer([\"The Brain is deeper than the sea\"]).numpy(),\n",
        "    \"\\n\",\n",
        ")\n",
        "\n",
        "# Create a Dense model\n",
        "inputs = keras.Input(shape=(1,), dtype=\"string\")\n",
        "x = text_vectorizer(inputs)\n",
        "outputs = layers.Dense(1)(x)\n",
        "model = keras.Model(inputs, outputs)\n",
        "\n",
        "# Call the model on test data (which includes unknown tokens)\n",
        "test_data = tf.constant([\"The Brain is deeper than the sea\"])\n",
        "test_output = model(test_data)\n",
        "print(\"Model output:\", test_output)"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "preprocessing_layers.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
